package com.flyme.module.base.provider.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.flyme.common.core.exception.OpenMessageException;
import com.flyme.core.base.supper.service.impl.BaseServiceImpl;
import com.flyme.module.base.client.constants.BaseConstants;
import com.flyme.module.base.client.entity.SysAuthority;
import com.flyme.module.base.client.entity.SystemMenu;
import com.flyme.module.base.client.enums.MenuTypeEnum;
import com.flyme.module.base.provider.mapper.SysMenuMapper;
import com.flyme.module.base.provider.service.SysAuthorizeService;
import com.flyme.module.base.provider.service.SysMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author zyf
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class SysMenuServiceImpl extends BaseServiceImpl<SysMenuMapper, SystemMenu> implements SysMenuService {
    @Autowired
    private SysAuthorizeService authorizeService;

    /**
     * 检查菜单编码是否存在
     *
     * @param menuCode
     * @return
     */
    @Override
    public Boolean isExist(String menuCode) {
        int count = count(q().eq("menuCode", menuCode));
        return count > 0;
    }

    /**
     * 添加菜单资源
     *
     * @param menu
     * @return
     */
    @Override
    public Boolean addMenu(SystemMenu menu) {
        if (isExist(menu.getName())) {
            throw new OpenMessageException(String.format("%s菜单编码已存在,不允许重复添加", menu.getName()));
        }
        if (menu.getParentId() == null) {
            menu.setParentId(0L);
        }
        if (menu.getPriority() == null) {
            menu.setPriority(new BigDecimal("0"));
        }
        if (menu.getStatus() == null) {
            menu.setStatus(BaseConstants.ENABLED);
        }
        if (menu.getIsPersist() == null) {
            menu.setIsPersist(BaseConstants.DISABLED);
        }
        menu.setCreateTime(new Date());
        menu.setUpdateTime(menu.getCreateTime());
        return save(menu);
    }

    /**
     * 修改菜单资源
     *
     * @param menu
     * @return
     */
    @Override
    public Boolean updateMenu(SystemMenu menu) {
        if (menu.getId() == null) {
            throw new OpenMessageException("ID不能为空");
        }
        SystemMenu savedMenu = getById(menu.getId());
        if (savedMenu == null) {
            throw new OpenMessageException(String.format("%s菜单不存在", menu.getId()));
        }
        if (!savedMenu.getName().equals(menu.getName())) {
            // 和原来不一致重新检查唯一性
            if (isExist(menu.getName())) {
                throw new OpenMessageException(String.format("%s菜单编码已存在,不允许重复添加", menu.getName()));
            }
        }
        if (menu.getParentId() == null) {
            menu.setParentId(0l);
        }
        if (menu.getPriority() == null) {
            menu.setPriority(new BigDecimal("0"));
        }
        menu.setUpdateTime(new Date());
        Boolean count = saveOrUpdate(menu);
        // 同步授权表里的信息
        authorizeService.updateGrantAccess(BaseConstants.RESOURCE_TYPE_MENU, menu.getId());
        return count;
    }

    /**
     * 更新启用禁用
     *
     * @param menuId
     * @param status
     * @return
     */
    @Override
    public Boolean updateStatus(Long menuId, Integer status) {
        SystemMenu menu = new SystemMenu();
        menu.setId(menuId);
        menu.setStatus(status);
        menu.setUpdateTime(new Date());
        Boolean count = saveOrUpdate(menu);
        // 同步授权表里的信息
        authorizeService.updateGrantAccess(BaseConstants.RESOURCE_TYPE_ACTION, menu.getId());
        return count;
    }

    /**
     * 移除菜单
     *
     * @param menuId
     * @return
     */
    @Override
    public Boolean removeMenu(Long menuId) {
        SystemMenu menu = getById(menuId);
        if (menu != null && menu.getIsPersist().equals(BaseConstants.ENABLED)) {
            throw new OpenMessageException(String.format("保留数据,不允许删除"));
        }
        if (authorizeService.isExist(menuId, BaseConstants.RESOURCE_TYPE_MENU)) {
            throw new OpenMessageException(String.format("资源已被授权,不允许删除,请取消授权后,再次尝试!", menuId));
        }
        return removeById(menuId);
    }

    @Override
    public List<SystemMenu> selectMenuByUserId(Long userId) {
        List<SystemMenu> menuList = baseMapper.selectMenuByUserId(userId);
        return buildTree(menuList, 0L);
    }

    @Override
    public List<SystemMenu> selectMenu(Long roleId) {
        List<SysAuthority> sysAuthorityList = authorizeService.findList(roleId.toString(), BaseConstants.AUTHORITY_PREFIX_ROLE, MenuTypeEnum.MENU.name());
        QueryWrapper cq = q().select("id", "title", "parentId").eq("menuType", MenuTypeEnum.MENU.getValue()).orderByAsc("priority");
        List<SystemMenu> list = list(cq);
        list.forEach(menu -> {
            Long menuId = menu.getId();
            sysAuthorityList.forEach(auth -> {
                Long resId = auth.getResourceId();
                if (resId.equals(menuId)) {
                    menu.setSelected(true);
                    menu.setChecked(true);
                }
            });
        });
        return buildTree(list, 0L);
    }

    /**
     * 递归构建
     *
     * @param list
     * @param parentId
     * @return
     */
    private static List<SystemMenu> buildTree(List<SystemMenu> list, Long parentId) {
        List menus = new ArrayList<SystemMenu>();
        list.forEach(resource -> {
            Long menuId = resource.getId();
            Long pid = resource.getParentId();
            if (parentId.equals(pid)) {
                List menuLists = buildTree(list, menuId);
                if (CollectionUtil.isNotEmpty(menuLists)) {
                    resource.setChildren(menuLists);
                    resource.setExpand(true);
                }
                menus.add(resource);
            }
        });
        return menus;
    }


}
